﻿using anydata.Entitys;
using MongoDB.Driver;
using Newtonsoft.Json.Linq;

namespace anydata.Services
{
    public class ThingLockService : ITransient, IPostReplace, IPostSetFields
    {
        private readonly DataProvider provider;

        public ThingLockService(DataProvider _provider)
        {
            provider = _provider;
        }

        public async Task Invoke(TokenModel token, string collectName, CollectSetFields data)
        {
            if (collectName == "work-instance")
            {
                var instanceStatus = data.Update.SelectToken("_set_.status");
                if (instanceStatus is not null && instanceStatus.Type == JTokenType.Integer)
                {
                    await Locking(token, data.Id, instanceStatus.Value<int>());
                }
            }
        }

        public async Task Invoke(TokenModel token, string collectName, List<EntityBase> list)
        {
            if (collectName == "work-instance")
            {
                foreach (var item in list)
                {
                    await Locking(token, item, item.status);
                }
            }
        }

        public async Task Locking(TokenModel token, EntityBase instanceObj, int status)
        {
            var instance = new XWorkInstance(instanceObj);
            if (instance?.InstanceData is not null)
            {
                var formMap = instance.InstanceData.FormCollectionNameMap;
                var infos = instance.InstanceData.infos;
                var result = provider.TryGetCollection<XTempData>(token, DataProvider.TempDataCollName);
                foreach (var (formId, things) in await instance.InstanceData.GetThings(result.data))
                {
                    if (formMap.ContainsKey(formId))
                    {
                        var collName = formMap[formId];
                        var info = infos[formId];
                        if (info is not null && (info.closeLock ?? false))
                        {
                            continue;
                        }
                        if (status < 100)
                        {
                            await LockThings(token, instance, collName, things);
                        }
                        else
                        {
                            await UnLockThings(token, collName, things);
                        }
                    }
                }
            }
        }

        public async Task Locking(TokenModel token, string id, int status)
        {
            try
            {
                var result = provider.TryGetCollection<EntityBase>(token, DataProvider.InstanceCollName);
                if (!result.success)
                {
                    Console.WriteLine("获取流程实例集合失败！");
                    return;
                }
                var instanceObj = await result.data.Find(i => i.id == id).FirstOrDefaultAsync();
                await Locking(token, instanceObj, status);
            }
            catch (Exception error)
            {
                Console.WriteLine("加解锁失败：", error.Message);
            }
        }

        public async Task LockThings(TokenModel token, XWorkInstance instance, string collName, List<EntityBase> things)
        {
            var coll = provider.TryGetCollection<EntityBase>(token, collName);
            if (coll.success)
            {
                try
                {
                    var filter = Builders<EntityBase>.Filter.In(item => item.id, things.Select(item => item.id).ToList());
                    var update = Builders<EntityBase>.Update.Set("locks.exclusion.id", instance.id).Set("locks.exclusion.name", instance.title);
                    await coll.data.UpdateManyAsync(filter, update);
                }
                catch (Exception error)
                {
                    Console.WriteLine("锁定失败：" + error.ToString());
                }
            }
        }

        public async Task UnLockThings(TokenModel token, string collName, List<EntityBase> things)
        {
            var coll = provider.TryGetCollection<EntityBase>(token, collName);
            if (coll.success)
            {
                try
                {
                    var filter = Builders<EntityBase>.Filter.In(item => item.id, things.Select(item => item.id).ToList());
                    var update = Builders<EntityBase>.Update.Unset("locks");
                    await coll.data.UpdateManyAsync(filter, update);
                }
                catch (Exception error)
                {
                    Console.WriteLine("解锁失败：" + error.ToString());
                }
            }
        }
    }
}
